using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace MetaView3D
{
    public partial class Form2 : Form
    {
        vtk.vtkRenderer aRenderer = new vtk.vtkRenderer();
        ///vtk.vtkRenderWindow renWin = new vtk.vtkRenderWindow();
        vtk.vtkRenderWindowInteractor iren = new vtk.vtkRenderWindowInteractor();
        vtk.vtkStructuredPointsReader reader2 = new vtk.vtkStructuredPointsReader();
        vtk.vtkImagePlaneWidget planeX = new vtk.vtkImagePlaneWidget();
        vtk.vtkContourFilter isoSurface = new vtk.vtkContourFilter();
        vtk.vtkWindowedSincPolyDataFilter smooth = new vtk.vtkWindowedSincPolyDataFilter();
        vtk.vtkPolyDataMapper surfaceMapper = new vtk.vtkPolyDataMapper();
        vtk.vtkActor surfaceActor = new vtk.vtkActor();
        vtk.vtkImagePlaneWidget planeY = new vtk.vtkImagePlaneWidget();
        vtk.vtkCellPicker picker = new vtk.vtkCellPicker();
        vtk.vtkImagePlaneWidget planeZ = new vtk.vtkImagePlaneWidget();
        vtk.vtkVolumeProperty volumeProperty = new vtk.vtkVolumeProperty();
        vtk.vtkPiecewiseFunction opacityTransferFunction = new vtk.vtkPiecewiseFunction();
        vtk.vtkColorTransferFunction colorTransferFunction = new vtk.vtkColorTransferFunction();
        vtk.vtkVolumeRayCastMIPFunction MIP = new vtk.vtkVolumeRayCastMIPFunction();
        vtk.vtkVolumeRayCastMapper volumeMapper = new vtk.vtkVolumeRayCastMapper();
        vtk.vtkOutlineFilter outlineData = new vtk.vtkOutlineFilter();
        vtk.vtkPolyDataMapper mapOutline = new vtk.vtkPolyDataMapper();
        vtk.vtkVolume volume = new vtk.vtkVolume();
        vtk.vtkActor outline = new vtk.vtkActor();
        vtk.vtkTextMapper textMapper = new vtk.vtkTextMapper();
        vtk.vtkActor2D textActor = new vtk.vtkActor2D();
        vtk.vtkCamera aCamera = new vtk.vtkCamera();
        UserActivityHook actHook = new UserActivityHook();
        vtk.vtkBoxWidget m_boxWidget;

        Boolean ShowSurface = true;
        int xslice = 20, yslice = 20, zslice = 20;
        int xmax, ymax, zmax;

        public Form2()
        {
            InitializeComponent();
            //OpenFileDialog OFD = new OpenFileDialog();
            //if ((OFD.ShowDialog() != DialogResult.OK))
            //{ return; }
            //LoadData(this.vtkFormsWindowControl1.GetRenderWindow(), OFD.FileName);
            //Load the Designer Components

        }
        public Form2(string Filename)
        {
            MessageBox.Show("Opening ... " + Filename.ToString());
            OpenFileDialog OFD = new OpenFileDialog();
            OFD.InitialDirectory = System.IO.Path.GetDirectoryName(Filename);
            if ((OFD.ShowDialog() != DialogResult.OK))
            { return; }
            InitializeComponent();
            
            LoadData(this.vtkFormsWindowControl1.GetRenderWindow(), OFD.FileName);
        }

        void LoadData(vtk.vtkRenderWindow renWin, string FileName)
        {
            //actHook.Stop();
            actHook.KeyPress += new KeyPressEventHandler(MyKeyPress);
            
            //# Create the renderer, the render window, and the interactor. The
            //# renderer draws into the render window, the interactor enables mouse-
            //# and keyboard-based interaction with the scene.
            renWin.AddRenderer(aRenderer);
            iren.SetInteractorStyle(new vtk.vtkInteractorStyleTrackballCamera());
            iren.SetRenderWindow(renWin);

            //# Read the volume images
            ///vtk.vtkStructuredPointsReader reader = new vtk.vtkStructuredPointsReader();
            ///reader.SetFileName("segmented.vtk");
            reader2.SetFileName(FileName);
            reader2.Update();
            int[] dim = new int[3];
            reader2.GetOutput().GetDimensions(dim);
            xmax = dim[0];
            ymax = dim[1];
            zmax = dim[2];
            xslice = dim[0] / 2;
            yslice = dim[1] / 2;
            zslice = dim[2] / 2;

            actHook.Start();

            //# Extracting a triangulated surface from the segmentation result
            //# Some smoothing is also done to get a nicer appearance
            isoSurface.SetInput(reader2.GetOutput());
            isoSurface.SetValue(0, 124);
            smooth.SetInput(isoSurface.GetOutput());
            surfaceMapper.SetInput(smooth.GetOutput());
            surfaceMapper.ScalarVisibilityOff();
            surfaceActor.SetMapper(surfaceMapper);
            surfaceActor.GetProperty().SetColor(1.0, 0.7, 0.0);

            //#We let the slice planes share the same picker
            picker.SetTolerance(0.005);

            //#X Slice plane
            planeX.SetInput(reader2.GetOutput());
            planeX.PlaceWidget();
            planeX.SetPlaneOrientationToXAxes();
            planeX.SetSliceIndex(this.xslice);
            planeX.SetInteractor(iren);
            planeX.SetPicker(picker);
            planeX.DisplayTextOn();
            planeX.SetCurrentRenderer(aRenderer);
            planeX.EnabledOn();

            //#Y Slice plane
            planeY.SetInput(reader2.GetOutput());
            planeY.PlaceWidget();
            planeY.SetPlaneOrientationToYAxes();
            planeY.SetSliceIndex(yslice);
            planeY.SetInteractor(iren);
            planeY.SetPicker(picker);
            planeY.DisplayTextOn();
            planeY.SetCurrentRenderer(aRenderer);
            planeY.EnabledOn();

            //#Z Slice plane
            planeZ.SetInput(reader2.GetOutput());
            planeZ.PlaceWidget();
            planeZ.SetPlaneOrientationToZAxes();
            planeZ.SetSliceIndex(zslice);
            planeZ.SetInteractor(iren);
            planeZ.SetPicker(picker);
            planeZ.DisplayTextOn();
            planeZ.SetCurrentRenderer(aRenderer);
            planeZ.EnabledOn();

            //# Adding the volume renderer (ray caster)
            opacityTransferFunction.AddPoint(20, 0.7);
            opacityTransferFunction.AddPoint(255, 1.0);

            colorTransferFunction.AddRGBPoint(0.0, 0.0, 0.0, 0.0);
            colorTransferFunction.AddRGBPoint(255.0, 1.0, 1.0, 1.0);

            volumeProperty.SetColor(colorTransferFunction);
            volumeProperty.SetScalarOpacity(opacityTransferFunction);

            volumeMapper.SetVolumeRayCastFunction(MIP);
            volumeMapper.SetInput(reader2.GetOutput());

            volume.SetMapper(volumeMapper);
            volume.SetProperty(volumeProperty);
            volume.VisibilityOff();

            //# Bounding box.
            outlineData.SetInput(reader2.GetOutput());
            mapOutline.SetInput(outlineData.GetOutput());
            outline.SetMapper(mapOutline);
            outline.GetProperty().SetColor(0, 0, 0);
            outline.GetProperty().SetOpacity(0.5);

            //#Adding text that describes the keyboard interface
            textMapper.SetInput("MetaView 3D.\nPowered by VTK");
            vtk.vtkTextProperty tprop = textMapper.GetTextProperty();
            tprop.SetFontFamily(2);
            tprop.SetFontSize(8);
            tprop.SetColor(1, 1, 1);
            textActor.SetMapper(textMapper);
            textActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay();
            textActor.GetPositionCoordinate().SetValue(0.0, 0.9);

            surfaceActor.VisibilityOff();

            //# Actors are added to the renderer. 
            aRenderer.AddActor(outline);
            aRenderer.AddActor(surfaceActor);
            aRenderer.AddActor(textActor);
            aRenderer.AddVolume(volume);
            aRenderer.SetActiveCamera(aCamera);

            //# Setting the color and size of the renderwindow,
            //#initializing the camera position
            aCamera.SetViewUp(0, 0, -1);
            aCamera.SetPosition(-2, -2, -2);
            aCamera.SetFocalPoint(0, 0, 0);
            aCamera.ComputeViewPlaneNormal();
            aRenderer.ResetCamera();
            aRenderer.ResetCameraClippingRange();
            aRenderer.SetBackground(0.2, 0.2, 0.2);

            iren = renWin.GetInteractor();

            {
                m_boxWidget = new vtk.vtkBoxWidget();
                m_boxWidget.SetInteractor(iren);
                m_boxWidget.SetPlaceFactor(1.0f);
                m_boxWidget.On();
            }
        }

        public void MyKeyPress(object sender, KeyPressEventArgs e)
        {
            if (iren != null)
            {
                if (e.KeyChar == 's')
                {
                    if (ShowSurface == true)
                    {
                        this.surfaceActor.VisibilityOn();
                        ShowSurface = false;
                    }
                    else
                    {
                        this.surfaceActor.VisibilityOff();
                        ShowSurface = true;
                    }
                }
                if (e.KeyChar == 'a')
                {                  
                    planeX.TextureVisibilityOff();
                    planeY.TextureVisibilityOff();
                    planeZ.TextureVisibilityOff();
                }

                if (e.KeyChar == 'x')
                {
                    xslice += 1;
                    if (xslice >= xmax) { xslice = 1; }
                    planeX.SetSliceIndex(xslice);
                }
                
                if (e.KeyChar == 'y')
                {
                    yslice += 1;
                    if (yslice >= ymax) { yslice = 1; }
                    planeY.SetSliceIndex(yslice);
                }

                if (e.KeyChar == 'z')
                {
                    if (zslice >= zmax) { zslice = 1; }
                    zslice += 1;
                    planeZ.SetSliceIndex(zslice);
                }
                this.vtkFormsWindowControl1.GetRenderWindow().Render();
            }
        }

        //void myCallback(vtk.vtkObject caller, uint eventId, object clientData, IntPtr callData)
        //{

        //    vtk.vtkRenderWindowInteractor iren = vtk.vtkRenderWindowInteractor.SafeDownCast(caller);
        //    }

        //
    }

    public class WriteVTK
    {
        public void Save(short[, ,] Data)
        {
            System.Windows.Forms.SaveFileDialog SFD = new System.Windows.Forms.SaveFileDialog();
            SFD.AddExtension = true;
            SFD.Title = "Save VTK file as ...";
            SFD.Filter = "VTK file (*.vtk)|*.vtk|All files (*.*)|*.*";
            if (SFD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                Save(Data, SFD.FileName);            
        }

        public void Save(short[, ,] Data, string Filename)
        {
            int x = Data.GetUpperBound(0) + 1;
            int y = Data.GetUpperBound(1) + 1;
            int z = Data.GetUpperBound(2) + 1;

            System.IO.FileInfo t = new System.IO.FileInfo(Filename);
            System.IO.StreamWriter tex = t.CreateText();
            tex.WriteLine("# vtk DataFile Version 3.0");
            tex.WriteLine("Created By MetaView");
            tex.WriteLine("ASCII");
            tex.WriteLine("DATASET STRUCTURED_POINTS");
            tex.WriteLine("DIMENSIONS " + x + " " + y + " " + z);
            tex.WriteLine("ORIGIN 0.0 0.0 0.0");
            tex.WriteLine("SPACING 1.0 1.0 1.0");
            tex.WriteLine("POINT_DATA " + x * y * z);
            tex.WriteLine("SCALARS image_data short");
            tex.WriteLine("LOOKUP_TABLE default");
            for (int k = 0; k <= z - 1; k++)
                for (int i = 0; i <= x - 1; i++)
                    for (int j = 0; j <= y - 1; j++)
                        tex.Write(Data[i, j, k] + " ");            
            tex.Close();
        }
    }
}
